package com.library.management.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.library.management.domain.OperationLogs;
import com.library.management.domain.Users;
import com.library.management.service.OperationLogsService;
import com.library.management.service.UsersService;
import com.library.management.mapper.OperationLogsMapper;
import com.library.management.dto.OperationLogQueryDTO;
import com.library.management.dto.OperationLogDetailDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author HY
* @description 针对表【operation_logs(操作日志表)】的数据库操作Service实现
* @createDate 2025-04-04 17:38:12
*/
@Slf4j
@Service
public class OperationLogsServiceImpl extends ServiceImpl<OperationLogsMapper, OperationLogs>
    implements OperationLogsService{

    @Autowired
    private UsersService usersService;

    /**
     * 分页查询操作日志
     * @param queryDTO 查询参数
     * @return 分页结果
     */
    @Override
    public Page<OperationLogs> getOperationLogPage(OperationLogQueryDTO queryDTO) {
        log.info("分页查询操作日志: pageNum={}, pageSize={}, actionType={}, operatorId={}", 
                queryDTO.getPageNum(), queryDTO.getPageSize(), queryDTO.getActionType(), queryDTO.getOperatorId());
        
        // 构建查询条件
        LambdaQueryWrapper<OperationLogs> queryWrapper = new LambdaQueryWrapper<>();
        
        // 按操作类型查询
        if (StringUtils.hasText(queryDTO.getActionType())) {
            queryWrapper.eq(OperationLogs::getActionType, queryDTO.getActionType());
        }
        
        // 按操作者ID查询
        if (queryDTO.getOperatorId() != null) {
            queryWrapper.eq(OperationLogs::getOperatorId, queryDTO.getOperatorId());
        }
        
        // 按时间倒序排序
        queryWrapper.orderByDesc(OperationLogs::getOperationTime);
        
        // 执行分页查询
        Page<OperationLogs> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        Page<OperationLogs> resultPage = page(page, queryWrapper);
        
        log.info("查询结果: 总记录数={}, 总页数={}", resultPage.getTotal(), resultPage.getPages());
        return resultPage;
    }
    
    /**
     * 分页查询操作日志详情
     * @param queryDTO 查询参数
     * @return 分页结果（包含详细信息）
     */
    @Override
    public Page<OperationLogDetailDTO> getOperationLogDetailPage(OperationLogQueryDTO queryDTO) {
        log.info("分页查询操作日志详情: pageNum={}, pageSize={}, actionType={}, operatorId={}", 
                queryDTO.getPageNum(), queryDTO.getPageSize(), queryDTO.getActionType(), queryDTO.getOperatorId());
        
        // 先获取原始日志数据
        Page<OperationLogs> originalPage = getOperationLogPage(queryDTO);
        List<OperationLogs> logs = originalPage.getRecords();
        
        // 如果没有日志，直接返回空结果
        if (logs.isEmpty()) {
            Page<OperationLogDetailDTO> emptyPage = new Page<>(
                    originalPage.getCurrent(), 
                    originalPage.getSize(), 
                    originalPage.getTotal());
            emptyPage.setRecords(new ArrayList<>());
            return emptyPage;
        }
        
        // 获取所有操作者ID（剔除null值）
        List<Integer> operatorIds = logs.stream()
                .map(OperationLogs::getOperatorId)
                .filter(id -> id != null)
                .distinct()
                .collect(Collectors.toList());
        
        // 批量查询用户信息
        Map<Integer, String> userIdToNameMap = new HashMap<>();
        if (!operatorIds.isEmpty()) {
            try {
                // 直接查询Users表获取用户名
                LambdaQueryWrapper<Users> userQuery = new LambdaQueryWrapper<>();
                userQuery.in(Users::getId, operatorIds);
                List<Users> users = usersService.list(userQuery);
                
                // 构建ID到用户名的映射
                for (Users user : users) {
                    if (user != null && user.getId() != null && user.getUsername() != null) {
                        userIdToNameMap.put(user.getId(), user.getUsername());
                        log.debug("用户映射: ID={}, 用户名={}", user.getId(), user.getUsername());
                    }
                }
                
                log.info("成功获取用户名映射: 用户数={}", userIdToNameMap.size());
            } catch (Exception e) {
                log.error("获取用户名映射失败: {}", e.getMessage());
            }
        }
        
        // 转换为详细DTO
        List<OperationLogDetailDTO> detailLogs = new ArrayList<>();
        for (OperationLogs log : logs) {
            OperationLogDetailDTO dto = convertToDetailDTO(log, userIdToNameMap);
            detailLogs.add(dto);
        }
        
        // 构建分页结果
        Page<OperationLogDetailDTO> resultPage = new Page<>(
                originalPage.getCurrent(),
                originalPage.getSize(),
                originalPage.getTotal());
        resultPage.setRecords(detailLogs);
        
        log.info("详细日志查询结果: 总记录数={}, 总页数={}", resultPage.getTotal(), resultPage.getPages());
        return resultPage;
    }
    
    /**
     * 将OperationLogs转换为详细DTO
     */
    private OperationLogDetailDTO convertToDetailDTO(OperationLogs log, Map<Integer, String> userIdToNameMap) {
        OperationLogDetailDTO dto = new OperationLogDetailDTO();
        dto.setId(log.getId());
        dto.setOperatorId(log.getOperatorId());
        
        // 设置操作者用户名（如果找不到则显示"未知用户"和ID）
        if (log.getOperatorId() != null && userIdToNameMap.containsKey(log.getOperatorId())) {
            dto.setOperatorName(userIdToNameMap.get(log.getOperatorId()));
        } else {
            dto.setOperatorName("未知用户(ID:" + log.getOperatorId() + ")");
        }
        
        dto.setActionType(log.getActionType());
        dto.setActionTypeDesc(getActionTypeDesc(log.getActionType()));
        dto.setTargetType(log.getTargetType());
        dto.setTargetTypeDesc(getTargetTypeDesc(log.getTargetType()));
        dto.setTargetId(log.getTargetId());
        dto.setDescription(log.getDescription());
        dto.setOperationTime(log.getOperationTime());
        dto.setIpAddress(log.getIpAddress());
        return dto;
    }
    
    /**
     * 获取操作类型的中文描述
     */
    private String getActionTypeDesc(String actionType) {
        if (actionType == null) return "未知操作";
        
        switch (actionType) {
            case "add": return "添加";
            case "update": return "更新";
            case "delete": return "删除";
            case "query": return "查询";
            case "import": return "导入";
            case "export": return "导出";
            case "login": return "登录";
            case "logout": return "登出";
            default: return actionType;
        }
    }
    
    /**
     * 获取目标类型的中文描述
     */
    private String getTargetTypeDesc(String targetType) {
        if (targetType == null) return "未知目标";
        
        switch (targetType) {
            case "book": return "图书";
            case "user": return "用户";
            case "category": return "分类";
            case "borrowing": return "借阅记录";
            case "system": return "系统";
            default: return targetType;
        }
    }
    
    /**
     * 记录操作日志
     * @param operatorId 操作者ID
     * @param actionType 操作类型
     * @param targetType 目标类型
     * @param targetId 目标ID
     * @param description 操作描述
     * @param ipAddress IP地址
     * @return 是否记录成功
     */
    @Override
    public boolean addOperationLog(Integer operatorId, String actionType, String targetType, 
                                 Integer targetId, String description, String ipAddress) {
        log.info("记录操作日志: operatorId={}, actionType={}, targetType={}, targetId={}", 
                operatorId, actionType, targetType, targetId);
        
        try {
            OperationLogs operationLog = new OperationLogs();
            operationLog.setOperatorId(operatorId);
            operationLog.setActionType(actionType);
            operationLog.setTargetType(targetType);
            operationLog.setTargetId(targetId);
            operationLog.setDescription(description);
            operationLog.setIpAddress(ipAddress);
            operationLog.setOperationTime(new Date());
            
            boolean saved = save(operationLog);
            log.info("操作日志记录{}", saved ? "成功" : "失败");
            return saved;
        } catch (Exception e) {
            log.error("记录操作日志失败: operatorId={}, actionType={}, error={}", 
                    operatorId, actionType, e.getMessage());
            return false;
        }
    }
}




